/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * http//www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is ART Ontology API.
 *
 * The Initial Developer of the Original Code is University of Roma Tor Vergata.
 * Portions created by University of Roma Tor Vergata are Copyright (C) 2008.
 * All Rights Reserved.
 *
 * The ART Ontology API were developed by the Artificial Intelligence Research Group
 * (art.uniroma2.it) at the University of Roma Tor Vergata
 * Current information about the ART Ontology API can be obtained at 
 * http//art.uniroma2.it/owlart
 *
 */

/*
 * Contributor(s): Armando Stellato stellato@info.uniroma2.it
 */
package it.uniroma2.art.owlart.utilities;

import it.uniroma2.art.owlart.model.ARTResource;
import it.uniroma2.art.owlart.model.ARTURIResource;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;

/**
 * A <code>PropertyChainsTree</code> is used to support all cases where a given operation must be performed
 * recursively from a given resource to all of its outbound resources by navigating exclusively given
 * propertyChains of properties.
 * 
 * @author Armando Stellato
 * @see {@link ModelUtilities#deepDeleteIndividual(ARTResource, it.uniroma2.art.owlart.models.RDFSModel, PropertyChainsTree)}
 * 
 */
public class PropertyChainsTree {

	private HashMap<ARTURIResource, PropertyChainsTree> propertyChains;

	/**
	 * this method is used to build the root of a PropertyChainsTree; following branches require no
	 * constructor and will be created through addChild(ARTResource newDelPropagProp)
	 */
	public PropertyChainsTree() {
		propertyChains = new HashMap<ARTURIResource, PropertyChainsTree>();
	}

	/**
	 * adds a child <code>PropertyChainsTree</code> with node value=<code>newChainedProp</code> and an empty
	 * propertyChains list
	 * 
	 * @param newChainedProp
	 * @return the newly added PropertyChainsTree
	 */
	public PropertyChainsTree addChainedProperty(ARTURIResource newChainedProp) {
		PropertyChainsTree newTree = new PropertyChainsTree();
		propertyChains.put(newChainedProp, newTree);
		return newTree;
	}

	/**
	 * will merge <code>chainedPropTree</code> into the current tree
	 * 
	 * @param chainedPropTree
	 */
	public void mergeTree(PropertyChainsTree chainedPropTree) {
		for (Entry<ARTURIResource, PropertyChainsTree> entry : chainedPropTree.propertyChains.entrySet()) {
			propertyChains.put(entry.getKey(), entry.getValue());
		}
	}

	public boolean hasChained(ARTURIResource chainedProp) {
		return propertyChains.containsKey(chainedProp);
	}

	public Collection<ARTURIResource> getChainedProperties() {
		return propertyChains.keySet();
	}

	/**
	 * get next chained properties starting from chainedProperty
	 * 
	 * @param chainedProperty
	 * @return
	 */
	public PropertyChainsTree getNextChain(ARTURIResource chainedProperty) {
		PropertyChainsTree chainedTree = propertyChains.get(chainedProperty);
		if (chainedTree != null)
			return chainedTree;
		else
			throw new IllegalArgumentException("property: " + chainedProperty
					+ " is not in the searched PropertyChainsTree");
	}

	/**
	 * get next propertyChains starting from the given chainedProperties. If they are more than one, the trees
	 * are merged into a new virtual chainedTree and returned
	 * 
	 * @param chainedProperty
	 * @return
	 */
	public PropertyChainsTree getNextChains(Collection<ARTURIResource> chainedProperties) {
		if (chainedProperties.size() == 1)
			return getNextChain(chainedProperties.iterator().next());

		// not size==1
		PropertyChainsTree newTree = new PropertyChainsTree();

		for (ARTURIResource chainedProp : chainedProperties) {
			newTree.mergeTree(getNextChain(chainedProp));
		}

		return newTree;
	}
}
